#include "sw_timer.h"

// 定时器链表头指针：所有运行中的定时器通过链表管理
static sw_timer_t* timer_list = NULL;
// 系统tick频率（Hz）：用于将毫秒转换为ticks（1 tick = 1000 / tick_freq 毫秒）
static uint32_t sys_tick_freq = 0;

/**
 * 初始化软件定时器模块
 * 功能：设置系统tick频率，初始化定时器链表
 */
void sw_timer_init(uint32_t tick_freq) {
    // 保存硬件定时器的频率（必须大于0，否则定时器无法正常工作）
    sys_tick_freq = tick_freq;
    // 初始化链表为空（无运行中的定时器）
    timer_list = NULL;
}

/**
 * 创建软件定时器实例
 * 功能：分配内存并初始化定时器参数
 */
sw_timer_t* sw_timer_create(sw_timer_mode_t mode, 
                           void (*timeout_func)(void*), 
                           void* user_data) {
    // 入参检查：回调函数不能为空，模块必须已初始化（sys_tick_freq > 0）
    if (timeout_func == NULL || sys_tick_freq == 0) {
        return NULL;
    }

    // 为定时器分配内存（若需无动态内存环境，可改为静态数组）
    sw_timer_t* timer = (sw_timer_t*)malloc(sizeof(sw_timer_t));
    if (timer == NULL) {
        return NULL; // 内存分配失败
    }

    // 初始化定时器成员
    timer->next = NULL;               // 初始不链接到任何节点
    timer->timeout_ticks = 0;         // 总定时ticks初始为0
    timer->remaining_ticks = 0;       // 剩余ticks初始为0
    timer->mode = mode;               // 设置用户指定的模式
    timer->state = SW_TIMER_STOPPED;  // 初始状态为停止
    timer->timeout_func = timeout_func; // 绑定回调函数
    timer->user_data = user_data;     // 保存用户数据

    return timer;
}

/**
 * 启动软件定时器
 * 功能：计算定时ticks，设置状态，并将定时器加入链表
 */
bool sw_timer_start(sw_timer_t* timer, uint32_t timeout_ms) {
    // 入参检查：定时器不能为空，定时时间不能为0，模块必须已初始化
    if (timer == NULL || timeout_ms == 0 || sys_tick_freq == 0) {
        return false;
    }

    // 计算总定时ticks：将毫秒转换为ticks（向上取整避免精度损失）
    // 公式：ticks = (ms * 频率) / 1000，加999是为了实现向上取整
    uint32_t timeout_ticks = (timeout_ms * sys_tick_freq + 999) / 1000;

    // 设置定时器的核心参数
    timer->timeout_ticks = timeout_ticks;  // 保存总定时ticks
    timer->remaining_ticks = timeout_ticks; // 初始化剩余ticks（从总ticks开始递减）
    timer->state = SW_TIMER_RUNNING;       // 状态改为运行中

    // 将定时器插入链表头部（头插法：简化实现，新定时器优先被处理）
    timer->next = timer_list;  // 新节点的next指向原链表头
    timer_list = timer;        // 链表头更新为新节点

    return true;
}

/**
 * 停止软件定时器
 * 功能：将定时器从链表中移除，状态改为停止
 */
void sw_timer_stop(sw_timer_t* timer) {
    // 入参检查：定时器为空或已停止，则无需处理
    if (timer == NULL || timer->state == SW_TIMER_STOPPED) {
        return;
    }

    // 从链表中删除当前定时器（双向指针法遍历链表）
    sw_timer_t**prev = &timer_list;  // prev指向当前节点的前一个节点的next指针
    while (*prev != NULL) {
        if (*prev == timer) {
            // 找到目标节点：将前一个节点的next指向当前节点的next，跳过当前节点
            *prev = timer->next;
            break;
        }
        // 未找到则继续遍历下一个节点
        prev = &(*prev)->next;
    }

    // 更新定时器状态为停止
    timer->state = SW_TIMER_STOPPED;
}

/**
 * 删除软件定时器
 * 功能：停止定时器并释放内存
 */
void sw_timer_delete(sw_timer_t* timer) {
    if (timer == NULL) {
        return;
    }
    // 先停止定时器（确保从链表中移除）
    sw_timer_stop(timer);
    // 释放定时器占用的内存
    free(timer);
}

/**
 * 软件定时器心跳函数
 * 功能：处理所有运行中定时器的计时，触发超时回调
 * 注意：此函数在硬件定时器中断中调用，需保证执行效率
 */
void sw_timer_tick(void) {
    sw_timer_t* current = timer_list;  // 当前遍历的节点
    // 无需prev指针，通过保存next节点避免链表断裂（回调中可能删除当前节点）

    while (current != NULL) {
        // 提前保存下一个节点：防止当前节点被删除后无法继续遍历
        sw_timer_t* next = current->next;

        // 仅处理运行中的定时器
        if (current->state == SW_TIMER_RUNNING) {
            // 剩余ticks大于0时，递减计时
            if (current->remaining_ticks > 0) {
                current->remaining_ticks--;

                // 剩余ticks为0：定时时间到
                if (current->remaining_ticks == 0) {
                    // 执行用户注册的回调函数（若不为空）
                    if (current->timeout_func != NULL) {
                        // 注意：回调函数在中断中执行，应尽量简短
                        current->timeout_func(current->user_data);
                    }

                    // 根据模式处理定时器后续状态
                    if (current->mode == SW_TIMER_ONE_SHOT) {
                        // 单次模式：定时结束后停止定时器（从链表移除）
                        sw_timer_stop(current);
                    } else {
                        // 周期模式：重置剩余ticks，继续下一次计时
                        current->remaining_ticks = current->timeout_ticks;
                    }
                }
            }
        }

        // 遍历下一个节点
        current = next;
    }
}